<script>
import render from './lib/render'
import { trigger } from './lib/config'

/**
 * Form Generator 组件的数据回显成表单的组件,适配JSON格式还为更新前的框架数据,
 * 新版本的Form Generator请使用官方自带* 的   * parser插件,使用npm 安装
 * 组件需要传递两个必须值
 * formConf: {
 *          type: Object,
 *          required: true
 *       },
 * drawingList: {
 *          type: Array,
 *           required: true
 *      }
 *      提交事件为@submit 在父组件使用提交事件
 */
function renderFrom(h) {
    const { formConfCopy, drawingListCopy } = this
    return (
        <el-row gutter={formConfCopy.gutter}>
            <el-form
                size={formConfCopy.size}
                label-position={formConfCopy.labelPosition}
                disabled={formConfCopy.disabled}
                label-width={`${formConfCopy.labelWidth}px`}
                ref={formConfCopy.formRef}
                // model不能直接赋值 https://github.com/vuejs/jsx/issues/49#issuecomment-472013664
                props={{ model: this[formConfCopy.formModel] }}
                rules={this[formConfCopy.formRules]}
            >
                {renderFormItem.call(this, h, drawingListCopy)}
                {formConfCopy.formBtns && formBtns.call(this, h)}
            </el-form>
        </el-row>
    )
}

function formBtns(h) {
    return <el-col>
        <el-form-item size="large">
            <el-button type="primary" onClick={this.submitForm}>提交</el-button>
            <el-button onClick={this.resetForm}>重置</el-button>
        </el-form-item>
    </el-col>
}

function renderFormItem(h, elementList) {
    return elementList.map(element => {
        const layout = layouts[element.layout]

        if (layout) {
            return layout.call(this, h, element)
        }
        throw new Error(`没有与${element.layout}匹配的layout`)
    })
}

function renderChildren(h, element) {
    if (!Array.isArray(element.children)) return null
    return renderFormItem.call(this, h, element.children)
}

const layouts = {
    colFormItem(h, element) {
        let labelWidth = element.labelWidth ? `${element.labelWidth}px` : null
        if (element.showLabel === false) labelWidth = '0'
        return (
            <el-col span={element.span}>
                <el-form-item label-width={labelWidth} prop={element.vModel}
                              label={element.showLabel ? '' : element.label}
                >
                    <render conf={element} onInput={event => {
                        this.$set(element, 'defaultValue', event)
                        this.$set(this[this.formConf.formModel], element.vModel, event)
                    }}
                    />
                </el-form-item>
            </el-col>
        )
    },
    rowFormItem(h, element) {
        let child = renderChildren.apply(this, arguments)
        if (element.type === 'flex') {
            child = <el-row type={element.type} justify={element.justify} align={element.align}>
                {child}
            </el-row>
        }
        return (
            <el-col span={element.span}>
                <el-row gutter={element.gutter}>
                    {child}
                </el-row>
            </el-col>
        )
    }
}

export default {
    components: {
        render
    },
    props: {
        formConf: {
            type: Object,
            required: true
        },
        drawingList: {
            type: Array,
            required: true
        }
    },
    data() {
        const data = {
            formConfCopy: this.formConf ? JSON.parse(JSON.stringify(this.formConf)) : {},
            drawingListCopy: this.drawingList ? JSON.parse(JSON.stringify(this.drawingList)) : []
        }
        this.initFormData(data, data.drawingListCopy, {})
        this.buildRules(data, data.drawingListCopy, {})
        return data
    },
    methods: {
        initFormData(data, componentList, initData) {
            data[this.formConf.formModel] = componentList.reduce((prev, cur) => {
                if (cur.vModel) prev[cur.vModel] = cur.defaultValue
                if (cur.children) this.initFormData(data, cur.children, prev)
                return prev
            }, initData)
        },
        buildRules(data, componentList, initData) {
            data[this.formConf.formRules] = componentList.reduce((prev, cur) => {
                if (Array.isArray(cur.regList)) {
                    if (cur.required) {
                        const required = { required: cur.required, message: cur.placeholder }
                        if (Array.isArray(cur.defaultValue)) {
                            required.type = 'array'
                            required.message = `请至少选择一个${cur.label}`
                        }
                        required.message === undefined && (required.message = `${cur.label}不能为空`)
                        cur.regList.push(required)
                    }
                    prev[cur.vModel] = cur.regList.map(item => {
                        item.pattern && (item.pattern = eval(item.pattern))
                        item.trigger = trigger[cur.tag]
                        return item
                    })
                }
                if (cur.children) this.buildRules(data, cur.children, prev)
                return prev
            }, initData)
        },
        resetForm() {
            if (this.drawingList) {
                this.drawingListCopy = JSON.parse(JSON.stringify(this.drawingList))
            }
            this.initFormData(this, this.drawingListCopy, {})
            this.$refs[this.formConf.formRef].resetFields()
        },
        submitForm() {
            this.$refs[this.formConf.formRef].validate(valid => {
                if (!valid) return false
                // TODO 提交表单
                // console.log('表单结果：', this[this.formConf.formModel])
                this.$emit('submit', this[this.formConf.formModel])
                return true
            })
        }
    },
    render(h) {
        return renderFrom.call(this, h)
    }
}
</script>
